import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards, Req, HttpStatus, UnauthorizedException } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiQuery, ApiParam } from '@nestjs/swagger';
import { ProjectService } from './project.service';
import { CreateProjectDto } from './dto/create-project.dto';
import { UpdateProjectDto } from './dto/update-project.dto';
import { ProjectResponseDto } from './dto/project-response.dto';
import { AddProjectMemberDto, UpdateProjectMemberDto, ProjectMemberResponseDto } from './dto/project-member.dto';
import { JwtAuthGuard } from '../../guards/jwt-auth.guard';
import { PermissionsGuard } from '../../guards/permissions.guard';
import { Permissions } from '../../decorators/permissions.decorator';
import { ProjectStatus } from '../../types/enums';
import { plainToClass } from 'class-transformer';
import { Request } from 'express';

interface RequestWithUser extends Request {
  user: {
    id: string;
    [key: string]: any;
  };
}

@ApiTags('项目管理')
@Controller('projects')
@UseGuards(JwtAuthGuard, PermissionsGuard)
@ApiBearerAuth()
export class ProjectController {
  constructor(private readonly projectService: ProjectService) {}

  @Post()
  @Permissions('project:create')
  @ApiOperation({ summary: '创建项目' })
  @ApiResponse({
    status: HttpStatus.CREATED,
    description: '项目创建成功',
    type: ProjectResponseDto,
  })
  async createProject(
    @Body() createProjectDto: CreateProjectDto,
    @Req() req: RequestWithUser,
  ): Promise<ProjectResponseDto> {
    if (!req.user) {
      throw new UnauthorizedException('用户未认证');
    }
    
    const userId = req.user.id;
    
    const project = await this.projectService.createProject(
      createProjectDto.name,
      createProjectDto.description,
      createProjectDto.workspaceId,
      new Date(createProjectDto.startDate),
      new Date(createProjectDto.endDate),
      createProjectDto.status,
      createProjectDto.priority,
      userId,
    );
    
    return plainToClass(ProjectResponseDto, project);
  }

  @Get()
  @Permissions('project:read')
  @ApiOperation({ summary: '获取项目列表' })
  @ApiQuery({
    name: 'workspaceId',
    required: false,
    description: '工作区ID',
    type: String,
  })
  @ApiQuery({
    name: 'status',
    required: false,
    description: '项目状态',
    enum: ProjectStatus,
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '获取项目列表成功',
    type: [ProjectResponseDto],
  })
  async getProjects(
    @Query('workspaceId') workspaceId?: string,
    @Query('status') status?: ProjectStatus,
  ): Promise<ProjectResponseDto[]> {
    const projects = await this.projectService.getProjects(workspaceId, status);
    return projects.map(project => plainToClass(ProjectResponseDto, project));
  }

  @Get(':id')
  @Permissions('project:read')
  @ApiOperation({ summary: '获取项目详情' })
  @ApiParam({
    name: 'id',
    description: '项目ID',
    type: String,
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '获取项目详情成功',
    type: ProjectResponseDto,
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: '项目不存在',
  })
  async getProjectById(@Param('id') id: string): Promise<ProjectResponseDto> {
    const project = await this.projectService.getProjectById(id);
    return plainToClass(ProjectResponseDto, project);
  }

  @Put(':id')
  @Permissions('project:update')
  @ApiOperation({ summary: '更新项目' })
  @ApiParam({
    name: 'id',
    description: '项目ID',
    type: String,
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '项目更新成功',
    type: ProjectResponseDto,
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: '项目不存在',
  })
  async updateProject(
    @Param('id') id: string,
    @Body() updateProjectDto: UpdateProjectDto,
  ): Promise<ProjectResponseDto> {
    const startDate = updateProjectDto.startDate ? new Date(updateProjectDto.startDate) : undefined;
    const endDate = updateProjectDto.endDate ? new Date(updateProjectDto.endDate) : undefined;
    
    const project = await this.projectService.updateProject(
      id,
      updateProjectDto.name,
      updateProjectDto.description,
      updateProjectDto.status,
      updateProjectDto.priority,
      startDate,
      endDate,
    );
    
    return plainToClass(ProjectResponseDto, project);
  }

  @Delete(':id')
  @Permissions('project:delete')
  @ApiOperation({ summary: '删除项目（软删除）' })
  @ApiParam({
    name: 'id',
    description: '项目ID',
    type: String,
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '项目删除成功',
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: '项目不存在',
  })
  async deleteProject(@Param('id') id: string): Promise<{ message: string }> {
    return this.projectService.deleteProject(id);
  }

  @Delete(':id/permanent')
  @Permissions('project:delete:permanent')
  @ApiOperation({ summary: '永久删除项目' })
  @ApiParam({
    name: 'id',
    description: '项目ID',
    type: String,
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '项目永久删除成功',
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: '项目不存在',
  })
  async hardDeleteProject(@Param('id') id: string): Promise<{ message: string }> {
    return this.projectService.hardDeleteProject(id);
  }

  @Get(':id/members')
  @Permissions('project:member:read')
  @ApiOperation({ summary: '获取项目成员列表' })
  @ApiParam({
    name: 'id',
    description: '项目ID',
    type: String,
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '获取项目成员列表成功',
    type: [ProjectMemberResponseDto],
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: '项目不存在',
  })
  async getProjectMembers(@Param('id') id: string): Promise<ProjectMemberResponseDto[]> {
    const members = await this.projectService.getProjectMembers(id);
    return members.map(member => plainToClass(ProjectMemberResponseDto, member));
  }

  @Post(':id/members')
  @Permissions('project:member:create')
  @ApiOperation({ summary: '添加项目成员' })
  @ApiParam({
    name: 'id',
    description: '项目ID',
    type: String,
  })
  @ApiResponse({
    status: HttpStatus.CREATED,
    description: '项目成员添加成功',
    type: ProjectMemberResponseDto,
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: '项目或用户不存在',
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: '用户已经是项目成员',
  })
  async addProjectMember(
    @Param('id') id: string,
    @Body() addMemberDto: AddProjectMemberDto,
  ): Promise<ProjectMemberResponseDto> {
    const member = await this.projectService.addProjectMember(
      id,
      addMemberDto.userId,
      addMemberDto.role,
    );
    return plainToClass(ProjectMemberResponseDto, member);
  }

  @Put(':id/members/:userId')
  @Permissions('project:member:update')
  @ApiOperation({ summary: '更新项目成员' })
  @ApiParam({
    name: 'id',
    description: '项目ID',
    type: String,
  })
  @ApiParam({
    name: 'userId',
    description: '用户ID',
    type: String,
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '项目成员更新成功',
    type: ProjectMemberResponseDto,
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: '项目或成员不存在',
  })
  async updateProjectMember(
    @Param('id') id: string,
    @Param('userId') userId: string,
    @Body() updateMemberDto: UpdateProjectMemberDto,
  ): Promise<ProjectMemberResponseDto> {
    const member = await this.projectService.updateProjectMember(
      id,
      userId,
      updateMemberDto.role,
      updateMemberDto.status,
    );
    return plainToClass(ProjectMemberResponseDto, member);
  }

  @Delete(':id/members/:userId')
  @Permissions('project:member:delete')
  @ApiOperation({ summary: '移除项目成员' })
  @ApiParam({
    name: 'id',
    description: '项目ID',
    type: String,
  })
  @ApiParam({
    name: 'userId',
    description: '用户ID',
    type: String,
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '项目成员移除成功',
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: '项目或成员不存在',
  })
  async removeProjectMember(
    @Param('id') id: string,
    @Param('userId') userId: string,
  ): Promise<{ message: string }> {
    return this.projectService.removeProjectMember(id, userId);
  }
} 